#include<iostream>
#include<functional>
#include<stdint.h>
#include<vector>
#include<unordered_map>
#include <memory>
#include <unistd.h>
using namespace std;


using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

//定时器任务对象
class TimeTask
{
private:
   uint64_t _id;//任务对象的id
   uint32_t _timeout;//定时任务的超时时间
   TaskFunc _task_cb; //定时器对象要执行的定制任务
   ReleaseFunc _release;//用于删除TimeWheel中保存的定时器对象信息
   bool _canceled;
 public:
  
    TimeTask(uint64_t id,uint32_t delay,const TaskFunc& cb)
    :_id(id),_timeout(delay),_task_cb(cb),_canceled(false)
    {}  
    //析构的时候执行定制任务并且销毁在定时轮中的该任务信息
    ~TimeTask()
    {
        if(!_canceled)
        _task_cb();
        _release();
    }
    //设置销毁定时器任务对象函数
    void SetRelease(const ReleaseFunc& cb)
    {
        _release = cb;
    }
    uint32_t DelayTime()
    {return _timeout;}

    void Cancel()
    {_canceled = true;}
};

//时间轮对象
class TimeWheel
{
private:
     using  WeakTask = std::weak_ptr<TimeTask>;
     using  PtrTask = std::shared_ptr<TimeTask>;
    
     int _tick;//表示执行定时任务的指针,走到哪里释放哪里,释放哪里相当于执行哪里的任务
     int _capacity;//相当于时间轮的一圈多少 --- 最大延迟时间
      vector<vector<PtrTask>> _wheel;//二维数组作为时间轮注意要比capacity后声明
     unordered_map<uint64_t,WeakTask> _timers; //注意这里需要使用WeakPtr是因为添加新的定时任务(shared_ptr<TimeTask>)再使用shared_Ptr会增加不必要的计数
     
     //从时间轮中删除定时任务
     void RemoveTimeTask(uint64_t id)
     {
         auto it = _timers.find(id);
         if(it != _timers.end())
            _timers.erase(it);
     }

public:
    TimeWheel()
    :_tick(0),_capacity(60),_wheel(_capacity)
    {}
    //在时间轮添加定时任务
    void TimerAdd(uint64_t id,uint32_t delay,const TaskFunc& cb)
    {
        //1.创建定时任务设置好删除函数
        PtrTask pt(new TimeTask(id,delay,cb));
        //注意:因为编译器不会将对象的成员函数隐式转换成函数指针，所以必须在TimeWheel::RemoveTimeTask前添加&；
        pt->SetRelease(std::bind(&TimeWheel::RemoveTimeTask,this,id));//注意这里需要使用bind这是因为RemoveTimeTask第一个参数是this,而且我们统一了ReleaseFunc
        cout << "Create Task.." << _wheel.size() << endl ;
        //2.存放到时间轮
        int pos = (_tick+delay)%_capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
    }
    //对指定定时任务进行刷新/延迟
    void RefreshTask(uint64_t id)
    {
        auto it = _timers.find(id);
         if(it == _timers.end())
            return; //没找到指定定时任务 返回
        PtrTask pt = it->second.lock();//相当于新建了一个shared_ptr共享计数
        int delay = pt->DelayTime();
        int pos = (_tick+delay)%_capacity;
        _wheel[pos].push_back(pt);
    }
    //指针移动执行任务
    void RunTimeTask()
    {
        _tick = (_tick+1)%_capacity;
        //走到哪释放哪
        _wheel[_tick].clear(); //清空指定位置的数组,就会把数组中保存的所有管理定时器对象的shared_ptr軽放掉
    }
    
    void CancelTask(uint64_t id)
    {
        auto it = _timers.find(id);
         if(it == _timers.end())
            return; //没找到指定定时任务 返回
        PtrTask pt = it->second.lock();//相当于新建了一个shared_ptr共享计数
        if(pt) pt->Cancel();
    }
};

class Test
{
public:
   Test()
   {cout << "test 构造..." << endl;}
   
   ~Test()
   {cout << "test 析构..." << endl;}
   
};

void DeleteTask(Test* t)
{
    delete t;
}

int main()
{
   TimeWheel tw;
   Test* t = new Test();
   
   tw.TimerAdd(666,5,std::bind(DeleteTask,t));
   cout << "Add Success!\n";
   //延迟
   for(int i = 0 ; i < 5 ;i++)
   {
      sleep(1);
      tw.RefreshTask(666);
      tw.RunTimeTask();//注意刷新的同时还要向后移动指针
      cout << "刷新了一下定时任务,重新需要5s后才能销毁\n";
   }
   //运行
   while(1)
   {
    sleep(1);
    cout << "------------------------\n";
    tw.RunTimeTask();//向后移动指针
   }
}